var fs = require('fs');
var path = require('path');
var url = require('url');
var http = require('http');
var logger = require('./logger');
var util = require('./util');
var conf = require('./conf');

var agent = new http.Agent({maxSockets: conf.MAX_SOCKETS});
var CACHE_DIR = util.mkdir(path.join(conf.CACHE, util.formatDate()));
var IMG_CACHE_DIR = conf.IMG;
var MAX_CONNECTIONS = 12; //最大并发数
var TIMEOUT = 36000;
var INTERVAL = 0; //下一个请求发出的间隔，默认立即发送
var connections = 0; //当前并发数
var gets = []; //缓存的get请求列表

var HEADERS = {
		'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
		'Accept-Language' : 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4',
		'Referer' : 'http://www.vvtrader.com/',
		'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36'
	};

function get(url, callback, isStream) {
	if (callback && typeof callback != 'function') {
		isStream = callback;
		callback = undefined;
	}
	
	if (connections > MAX_CONNECTIONS) {
		gets.push({
			url: url,
			callback: callback,
			isStream: isStream
		});
		return;
	}
	
	callback = callback || util.noop;
	++connections;
	
	if (isStream) {
		getStream(url, callback);
		return;
	}
	var filePath = path.join(CACHE_DIR, encodeURIComponent(url));
	fs.readFile(filePath, 'utf8', function(err, body) {
		if (err || !body) {
			logger.info('Load URL: ' + url);
			request(url, function(res) {
				if (res.statusCode != 200) {
					callback(null, '');
					logger.info('http status: ' + res.statusCode + ' ' + url);
					return;
				}
				res.setEncoding('utf8');
				var body = '';
				res.on('data', function(data) {
					body += data;
				});
				
				res.on('end', function() {
					fs.writeFile(filePath, body, function(err, data) {
						  callback(null, body);
						  getNext();
					  });
					logger.info('Successfully loaded URL: ' + url);
				});
			}).on('error', function(err) {
				gets.push({
					url: url,
					callback: callback
				});
				 getNext();
				 logger.error('Failed to loaded URL: ' + url);
				 logger.error(err);
			});
		} else {
			logger.info('From cache file: ' + filePath);
			callback(null, body);
			getNext();
		}
	});
}

function getStream(url, callback) {
	var filePath = path.join(IMG_CACHE_DIR, getFileName(url));
	fs.exists(filePath, function(exists) {
		var handleSuccess = function(cache) {
			callback(null, filePath);
			getNext();
			logger.info(cache ? 'From cache file: ' + filePath : 'Successfully loaded URL: ' + url);
		};
		
		var handleError = function(err) {
			callback(err);
			gets.push({
				url: url,
				callback: callback,
				isStream: true
			});
			getNext();
			logger.error('Failed to loaded URL: ' + url);
			logger.error(err);
		};
		
		if(exists) {
			handleSuccess(true);
			return;
		}
		
		logger.info('Load stream URL: ' + url);
		
		request(url, function(res) {
			if (res.statusCode == 200) {
				res.pipe(fs.createWriteStream(filePath))
				.on('error', handleError)
				 .on('finish', handleSuccess);
			} else {
				logger.info('http status: ' + res.statusCode + ' ' + url);
			}
		}).on('error',handleError);
	});
}

function getFileName(url) {
	url = url.replace(/(\?|#).*$/, '');
	return url.substring(url.lastIndexOf('/') + 1);
}

function request(_url, callback) {
	var options = url.parse(_url);
	options.agent = agent;
	options.headers = HEADERS;
	
	var client = http.request(options, function(res) {
		if (res.statusCode >= 500) {
			util.drain(res);
			client.emit('error', new Error('http error: ' + res.statusCode));
			return;
		}
		callback(res);
	});
	client.end();
	client.setTimeout(TIMEOUT, function() {
		client.abort();
	});
	
	return client;
}

function getNext() {
	if (INTERVAL > 0) {
		setTimeout(_getNext, INTERVAL);
	} else {
		_getNext();
	}
}

function _getNext() {
	if (--connections < MAX_CONNECTIONS) {
		  var options = gets.shift();
		  if (options) {
			  get(options.url, options.callback, options.isStream);
		  } else if (connections < 1) {
			  setTimeout(function() {
				  process.emit('loaderIdle');
			  }, 1000);
		  }
	  }
}

module.exports.get = get;
